package com.example.demo.api;

import com.example.demo.common.AppVariable;
import com.example.demo.entity.User;
import com.example.demo.game.*;
import com.example.demo.mapper.UserMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Component
public class GameAPI extends TextWebSocketHandler {

    private ObjectMapper objectMapper = new ObjectMapper();
    @Resource
    private RoomManager roomManager;
    @Resource
    private OnlineUserMapper onlineUserMapper;
    @Resource
    private UserMapper userMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        GameReadyResponse response = new GameReadyResponse();

        // 1. 先获取用户的身份信息（从httpsession里拿）
        User user =(User) session.getAttributes().get(AppVariable.USER_SESSION_KEY);
        if(user == null ) {
            response.setOk(false);
            response.setReason("用户尚未登录！");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
             //session.close();
            return;
        }
        // 2. 判定当前用户是否已经进入房间。 （房间管理器进行查询）
        Room room = roomManager.getRoomByUserId(user.getUserId());
        if(room == null) {
            // 没有找到对应的房间，还未匹配到
            response.setOk(false);
            response.setReason("用户尚未匹配到！");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));

        }
        // 3. 判定当前是不是多开

        if(onlineUserMapper.getFromGameHall(user.getUserId()) != null
                && onlineUserMapper.getFromGameRoom(user.getUserId()) != null) {
            // 一边在大厅 一边房间 也属于多开
            response.setOk(true);
            response.setReason("禁止多开游戏页面！");
            response.setMessage("repeatConnection");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }

        // 4.设置玩家上线！
        onlineUserMapper.enterGameRoom(user.getUserId(), session);

        synchronized (room) {
            // 5.把两个玩家加入到游戏房间中
            if(room.getUser1() == null) {
                room.setUser1(user);
                //先手玩家
                room.setWhiteUser(user.getUserId());
                System.out.println("玩家：" + user.getUsername() + " 已经准备就绪！作为玩家1");
                return;
            }
            if(room.getUser2()  == null) {
                room.setUser2(user);
                System.out.println("玩家：" + user.getUsername() + " 已经准备就绪！作为玩家2");

                // 通知双方就绪
                noticeGameReady(room,room.getUser1(),room.getUser2());
                noticeGameReady(room,room.getUser2(),room.getUser1());
                return;
            }
        }


        // 6. 有别的玩家尝试连接同一个房间，提示报错
        response.setOk(false);
        response.setReason("当前房间已满！不能加入房间");
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));


    }

    private void noticeGameReady(Room room, User thisUser, User thatUser) throws IOException {

        GameReadyResponse resp = new GameReadyResponse();

        resp.setOk(true);
        resp.setReason("");
        resp.setMessage("gameReady");
        resp.setRoomId(room.getRoomId());
        resp.setThisUserId(thisUser.getUserId());
        resp.setThatUserId(thatUser.getUserId());
        resp.setWhiteUser(room.getWhiteUser());
        WebSocketSession webSocketSession = onlineUserMapper.getFromGameRoom(thisUser.getUserId());
            webSocketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));


    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        // 1. 先从session里拿到当前的用户身份信息
        User user = (User) session.getAttributes().get(AppVariable.USER_SESSION_KEY);
        if( user == null) {
            System.out.println("[handleTextMessage]  当前玩家尚未登录！");
            return;
        }

        // 2. 根据玩家id 获取到房间对象
        Room room = roomManager.getRoomByUserId(user.getUserId());
        // 3. 通过room对象来处理这的请求
        room.putChess(message.getPayload());

    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        User user = (User) session.getAttributes().get(AppVariable.USER_SESSION_KEY);

        if( user == null) {

            return;
        }
        WebSocketSession exitSession = onlineUserMapper.getFromGameRoom(user.getUserId());

        if( session == exitSession) {
            onlineUserMapper.exitGameRoom(user.getUserId());
        }

        System.out.println("当前用户：" + user.getUsername() + " 游戏房间连接异常！");
// 通知对手获胜了
        noticeThatUserWin(user);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

        User user = (User) session.getAttributes().get(AppVariable.USER_SESSION_KEY);

        if( user == null) {

            return;
        }
        WebSocketSession exitSession = onlineUserMapper.getFromGameRoom(user.getUserId());

        if( session == exitSession) {
            onlineUserMapper.exitGameRoom(user.getUserId());
        }

        System.out.println("当前用户：" + user.getUsername() + " 离开游戏房间！");
// 通知对手获胜了
        noticeThatUserWin(user);
    }
    private void noticeThatUserWin(User user) throws IOException {
        // 1. 根据当前玩家, 找到玩家所在的房间
        Room room = roomManager.getRoomByUserId(user.getUserId());
        if (room == null) {
            // 这个情况意味着房间已经被释放了, 也就没有 "对手" 了
            System.out.println("当前房间已经释放, 无需通知对手!");
            return;
        }

        // 2. 根据房间找到对手
        User thatUser = (user == room.getUser1()) ? room.getUser2() : room.getUser1();
        // 3. 找到对手的在线状态
        WebSocketSession webSocketSession = onlineUserMapper.getFromGameRoom(thatUser.getUserId());
        if (webSocketSession == null) {
            // 这就意味着对手也掉线了!
            System.out.println("对手也已经掉线了, 无需通知!");
            return;
        }
        // 4. 构造一个响应, 来通知对手, 你是获胜方
        GameResponse resp = new GameResponse();
        resp.setMessage("putChess");
        resp.setUserId(thatUser.getUserId());
        resp.setWinner(thatUser.getUserId());
        webSocketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));

        // 5. 更新玩家的分数信息
        int winUserId = thatUser.getUserId();
        int loseUserId = user.getUserId();
        userMapper.userWin(winUserId);
        userMapper.userLose(loseUserId);

        // 6. 释放房间对象
        roomManager.remove(room.getRoomId(), room.getUser1().getUserId(), room.getUser2().getUserId());
    }
}
